using System;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace System.Web.Core 
{
    public class Pager : Label, IPagedControl, INamingContainer 
    {
        #region Member variables and constructor

        private HttpContext context = HttpContext.Current;
        private HyperLink previousLink;
        private HyperLink nextLink;
        private HyperLink firstLink;
        private HyperLink lastLink;
        private HyperLink[] pagingHyperLinks;

        public override ControlCollection Controls 
        {
            get 
            {
                EnsureChildControls();
                return base.Controls;
            }
        }
        protected override void CreateChildControls() 
        {
            Controls.Clear();

            // Add Page buttons
            //
            AddPageLinks();

            // Add Previous Next child controls
            //
            AddPreviousNextLinks();

            // Add First Last child controls
            //
            AddFirstLastLinks();

        }

        #endregion

        #region Render functions

        protected override void Render(HtmlTextWriter writer) 
        {

            int totalPages = TotalPages;

            // Do we have entity?
            //
            if (totalPages <= 1)
                return;

            // Render the paging buttons
            //
            writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass, false);

            // Render the first button
            //
            RenderFirst(writer);

            // Render the previous button
            //
            RenderPrevious(writer);
            
            // Render the page button(s)
            //
            RenderPagingButtons(writer);

            // Render the next button
            //
            RenderNext(writer);

            // Render the last button
            //
            RenderLast(writer);

            //writer.RenderEndTag();

        }

        void RenderFirst (HtmlTextWriter writer) 
        {

            int totalPages = TotalPages;

            if ((PageIndex >= 3) && (totalPages > 5)) 
            {
                firstLink.RenderControl(writer);

                LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
                l.RenderControl(writer);
            }
        }

        void RenderLast (HtmlTextWriter writer) 
        {
            int totalPages = TotalPages;

            if (((PageIndex + 3) < totalPages) && (totalPages > 5)) 
            {
                LiteralControl l = new LiteralControl("&nbsp;...&nbsp;");
                l.RenderControl(writer);

                if (TotalPages <= 1000)
                {
                    lastLink.RenderControl(writer);
                }
            }
        }

        void RenderPrevious (HtmlTextWriter writer) 
        {
            Literal l;

            if (HasPrevious) 
            {
                previousLink.RenderControl(writer);

                l = new Literal();
                l.Text = "&nbsp;";
                l.RenderControl(writer);
            }

        }

        void RenderNext(HtmlTextWriter writer) 
        {
            Literal l;

            if (HasNext) 
            {

                l = new Literal();
                l.Text = "&nbsp;";
                l.RenderControl(writer);

                nextLink.RenderControl(writer);
            }

        }

        void RenderButtonRange(int start, int end, HtmlTextWriter writer) 
        {

            for (int i = start; i < end; i++) 
            {

                // Are we working with the selected index?
                //
                if (PageIndex == i) 
                {

                    // Render different output
                    //
                    Literal l = new Literal();
                    //l.Text = "<span class=\"currentPage\">[" + (i + 1).ToString() + "]</span>";
                    l.Text = (i + 1).ToString();

                    l.RenderControl(writer);
                } 
                else 
                {
                    pagingHyperLinks[i - start].RenderControl(writer);
                }
                if ( i < (end - 1) )
                    writer.Write(" ");

            }

        }

        void RenderPagingButtons(HtmlTextWriter writer) 
        {
            int totalPages;

            // Get the total pages available
            //
            totalPages = TotalPages;

            // If we have <= 5 pages display all the pages and exit
            //
            if ( totalPages <= 5) 
            {
                RenderButtonRange(0, totalPages, writer);
            } 
            else 
            {

                int lowerBound = (PageIndex - 2);
                int upperBound = (PageIndex + 3);

                if (lowerBound < 0)
                {
                    lowerBound = 0;
                }

                if (PageIndex == 0)
                    RenderButtonRange(0, 5, writer);

                else if (PageIndex == 1)
                    RenderButtonRange(0, (PageIndex + 4), writer);

                else if (PageIndex < (totalPages - 2))
                    RenderButtonRange(lowerBound, (PageIndex + 3), writer);

                else if (PageIndex == (totalPages - 2))
                    RenderButtonRange((totalPages - 5), (PageIndex + 2), writer);

                else if (PageIndex == (totalPages - 1))
                    RenderButtonRange((totalPages - 5), (PageIndex + 1), writer);
            }
        }

        #endregion

        #region ControlTree functions
        void AddPageLinks() 
        {
            int lowerBound = (PageIndex - 2);
            int upperBound = (PageIndex + 3);

            if (lowerBound <= 0)
            {
                lowerBound = 0;
            }

            if (PageIndex == 0 || PageIndex == 1)
            {
                lowerBound = 0;
                upperBound = 5;
            }
            else if (PageIndex < (TotalPages - 2))
            {
                upperBound = PageIndex + 3;
            }
            else if (PageIndex == (TotalPages - 2))
            {
                lowerBound = TotalPages - 5;
                upperBound = PageIndex + 2;
            }
            else if (PageIndex == (TotalPages - 1))
            {
                lowerBound = TotalPages - 5;
                upperBound = PageIndex + 1;
            }

            if (lowerBound < 0)
            {
                lowerBound = 0;
            }
            // First add the lower page buttons
            //
            pagingHyperLinks = new HyperLink[upperBound - lowerBound];

            // Create the buttons and add them to 
            // the Controls collection
            //
            for (int i = lowerBound; i < upperBound; i++) 
            {
                pagingHyperLinks[i - lowerBound] = new HyperLink();
                pagingHyperLinks[i - lowerBound].EnableViewState = false;
                pagingHyperLinks[i - lowerBound].Text = (i + 1).ToString();
                pagingHyperLinks[i - lowerBound].ID = (i + 1).ToString();
                pagingHyperLinks[i - lowerBound].NavigateUrl = CreatePagerURL((i + 1).ToString());
                Controls.Add(pagingHyperLinks[i - lowerBound]);
            }
        }

        void AddFirstLastLinks() 
        {
            int start = 1;
            firstLink = new HyperLink();
            firstLink.ID = "First";
            firstLink.Text = ResourceManager.GetString("Utility_Pager_firstButton");
            firstLink.NavigateUrl = CreatePagerURL(start.ToString());
            Controls.Add(firstLink);

            int last = TotalPages;
            lastLink = new HyperLink();
            lastLink.ID = "Last";
            lastLink.Text = ResourceManager.GetString("Utility_Pager_lastButton");
            lastLink.NavigateUrl = CreatePagerURL(last.ToString());
            Controls.Add(lastLink);
        }

        void AddPreviousNextLinks() 
        {
            int previous;
            
            if (this.PageIndex < 2)
                previous = 1;
            else
                previous = this.PageIndex;

            previousLink = new HyperLink();
            previousLink.ID = "Prev";
            previousLink.Text = ResourceManager.GetString("Utility_Pager_previousButton");
            previousLink.NavigateUrl = CreatePagerURL(previous.ToString());
            Controls.Add(previousLink);

            int next = this.PageIndex + 2;
            nextLink = new HyperLink();
            nextLink.ID = "Next";
            nextLink.Text = ResourceManager.GetString("Utility_Pager_nextButton");
            nextLink.NavigateUrl = CreatePagerURL(next.ToString());
            Controls.Add(nextLink);
        }
        #endregion

        #region Private Properties
        private bool HasPrevious 
        {
            get 
            {
                if (PageIndex > 0)
                    return true;

                return false;
            }
        }

        private bool HasNext 
        {
            get 
            {
                if (PageIndex + 1 < TotalPages )
                    return true;

                return false;
            }
        }
        #endregion

        #region Helper methods and Public Properties

        protected virtual string CreatePagerURL(string pageIndex)
        {
            if(!string.IsNullOrEmpty(UrlPattern))
                return string.Format(UrlPattern,pageIndex);

            if (!string.IsNullOrEmpty(UrlName))
            {
                return UrlManager.Instance.FormatUrl(UrlName, new object[] { pageIndex });
            }

            string pageIndexParameterName = UrlManager.Instance.GetParameterName(ParameterName.PageIndex);
            string rawUrl = context.Request.RawUrl;

            if (rawUrl.IndexOf("?") == -1)
            {
                return rawUrl + "?" + pageIndexParameterName + "=" + pageIndex;
            }
            else
            {
                if (rawUrl.IndexOf(pageIndexParameterName + "=", StringComparison.CurrentCultureIgnoreCase) == -1)
                {
                    return rawUrl + "&" + pageIndexParameterName + "=" + pageIndex;
                }
                else
                {
                    return Regex.Replace(rawUrl, @"PageIndex=(\d+\.?\d*|\.\d+)", pageIndexParameterName + "=" + pageIndex, RegexOptions.IgnoreCase);
                }
            }
        }

        string _urlPattern = null;
        public string UrlPattern
        {
            get { return _urlPattern;}
            set {_urlPattern = value;}
        }

        string _urlName = null;
        public string UrlName
        {
            get { return _urlName; }
            set { _urlName = value; }
        }


        public virtual int CalculateTotalPages(int totalRecords) 
        {
            int totalPagesAvailable;

            if (totalRecords == 0)
                return 0;

            // First calculate the division
            //
            totalPagesAvailable = totalRecords / PageSize;

            // Now do a mod for any remainder
            //
            if ((totalRecords % PageSize) > 0)
                totalPagesAvailable++;

            return totalPagesAvailable;

        }

        int _pageIndex = 0;
        public virtual int PageIndex 
        {
            get 
            {
                // Give first try to the ViewState if it was a postback
                if (Page != null && Page.IsPostBack && ViewState["PageIndex"] != null){
                    _pageIndex = (int) ViewState["PageIndex"];
                }
                else {
                    if (context.Request.QueryString["pageindex"] != null)
                        _pageIndex = int.Parse(context.Request.QueryString["pageindex"]) - 1;
                }

                if (_pageIndex < 0)
                    return 0;
                else
                    return _pageIndex;
            }
            set 
            {
                ViewState["PageIndex"] = value;
                _pageIndex = value;
            }
        }

        public virtual int PageSize 
        {
            get 
            {
                int pageSize = Convert.ToInt32(ViewState["PageSize"]);

                if (pageSize == 0) 
                    return 10;

                return pageSize;
            }
            set 
            {
                ViewState["PageSize"] = value;
            }

        }

        private bool _causeValidation = true;
        public bool CausesValidation
        {
            get {return _causeValidation;}
            set {_causeValidation = value;}
        }

        public int TotalPages
        {
            get
            {
                return Convert.ToInt32(ViewState["TotalPages"]);
            }
            set
            {
                ViewState["TotalPages"] = value;
            }
        }

        public string UrlCleaner(string RawURL, string QueryName)
        {
            // Configure the Url
            if(RawURL.IndexOf("?") != -1)
            {
                bool hasPart = false;
                string queryString = RawURL.Substring( RawURL.IndexOf("?") + 1 );
                string[] parts = queryString.Split('&');
                for(int i = 0 ; i < parts.Length ; i++)
                {
                    if(parts[i].StartsWith(QueryName))
                    {
                        parts[i] = QueryName + "={0}";
                        hasPart = true;
                    }
                }
                if(hasPart == true)
                    RawURL = RawURL.Replace(queryString, string.Join("&", parts));
                else
                    RawURL = RawURL.Replace(queryString, string.Join("&", parts) + "&" + QueryName + "={0}");
            }
            else
                RawURL = RawURL + "?" + QueryName + "={0}";

            return RawURL;

        }

        #endregion
    }
}